/**
 * WebSocket 实时通信服务 - 基于 SignalR
 */

import * as signalR from '@microsoft/signalr'
import { getToken } from './auth'

/**
 * 任务日志数据
 */
export interface TaskLogData {
  taskId: number
  pipelineInstanceId: number
  logLevel: string
  logContent: string
  timestamp: string
}

/**
 * 任务状态数据
 */
export interface TaskStatusData {
  taskId: number
  pipelineInstanceId: number
  status: number
  progress: number
  errorMessage?: string
  timestamp: string
}

/**
 * 节点状态数据
 */
export interface NodeStatusData {
  nodeId: number
  nodeName: string
  nodeKey: string
  isOnline: boolean
  cpuUsage: number
  memoryUsage: number
  runningTasks: number
  availableDiskSpaceMB: number
  supportedEnvironments: string[]
  lastHeartbeatTime: string
  eventType: 'registered' | 'online' | 'offline'
  timestamp: string
}

/**
 * SignalR Hub 方法
 */
export const HubMethod = {
  // 订阅方法
  SUBSCRIBE_TASK_LOGS: 'SubscribeTaskLogs',
  UNSUBSCRIBE_TASK_LOGS: 'UnsubscribeTaskLogs',
  SUBSCRIBE_TASK_STATUS: 'SubscribeTaskStatus',
  UNSUBSCRIBE_TASK_STATUS: 'UnsubscribeTaskStatus',
  SUBSCRIBE_NODE_STATUS: 'SubscribeNodeStatus',
  UNSUBSCRIBE_NODE_STATUS: 'UnsubscribeNodeStatus',
  SUBSCRIBE_PIPELINE_INSTANCE: 'SubscribePipelineInstance',
  UNSUBSCRIBE_PIPELINE_INSTANCE: 'UnsubscribePipelineInstance',
} as const
export type HubMethod = typeof HubMethod[keyof typeof HubMethod]

/**
 * SignalR 接收事件
 */
export const HubEvent = {
  RECEIVE_TASK_LOG: 'ReceiveTaskLog',
  RECEIVE_TASK_STATUS: 'ReceiveTaskStatus',
  RECEIVE_NODE_STATUS: 'ReceiveNodeStatus',
} as const
export type HubEvent = typeof HubEvent[keyof typeof HubEvent]

type EventCallback<T = any> = (data: T) => void

/**
 * SignalR WebSocket 服务
 */
class SignalRService {
  private connection: signalR.HubConnection | null = null
  private eventHandlers: Map<string, Set<EventCallback>> = new Map()
  private isConnecting = false

  /**
   * 建立 SignalR 连接
   */
  async connect(): Promise<void> {
    if (this.connection?.state === signalR.HubConnectionState.Connected) {
      console.log('SignalR already connected')
      return
    }

    if (this.isConnecting) {
      console.log('SignalR connection in progress, waiting...')
      // 等待当前连接尝试完成
      return new Promise((resolve, reject) => {
        const checkInterval = setInterval(() => {
          if (!this.isConnecting) {
            clearInterval(checkInterval)
            if (this.connection?.state === signalR.HubConnectionState.Connected) {
              resolve()
            } else {
              reject(new Error('Connection attempt failed'))
            }
          }
        }, 100)

        // 10秒超时
        setTimeout(() => {
          clearInterval(checkInterval)
          reject(new Error('Connection timeout'))
        }, 10000)
      })
    }

    const token = getToken()
    if (!token) {
      console.warn('No authentication token found, skipping SignalR connection')
      throw new Error('No authentication token')
    }

    // 获取 WebSocket URL,SignalR 使用 HTTP/HTTPS 协议
    const wsUrl = import.meta.env.VITE_WS_URL || 'http://localhost:5136'
    const hubUrl = `${wsUrl}/hubs/devops`
    console.log('SignalR connecting to:', hubUrl)

    this.isConnecting = true

    try {
      this.connection = new signalR.HubConnectionBuilder()
        .withUrl(hubUrl, {
          accessTokenFactory: () => token,
        })
        .withAutomaticReconnect({
          nextRetryDelayInMilliseconds: (retryContext) => {
            // 重连延迟策略: 0s, 2s, 10s, 30s, 60s
            if (retryContext.elapsedMilliseconds < 60000) {
              return Math.min(
                1000 * Math.pow(2, retryContext.previousRetryCount),
                60000
              )
            }
            return null // 停止重连
          },
        })
        .configureLogging(signalR.LogLevel.Information)
        .build()

      this.setupEventHandlers()

      await this.connection.start()
      console.log('SignalR connected successfully')
    } catch (error) {
      console.error('SignalR connection failed:', error)
      this.connection = null
      throw error
    } finally {
      this.isConnecting = false
    }
  }

  /**
   * 设置 SignalR 事件处理器
   */
  private setupEventHandlers(): void {
    if (!this.connection) return

    // 监听连接关闭
    this.connection.onclose((error) => {
      console.log('SignalR connection closed', error)
      this.emit('disconnect', error)
    })

    // 监听重连中
    this.connection.onreconnecting((error) => {
      console.warn('SignalR reconnecting...', error)
      this.emit('reconnecting', error)
    })

    // 监听重连成功
    this.connection.onreconnected((connectionId) => {
      console.log('SignalR reconnected', connectionId)
      this.emit('reconnected', connectionId)
    })

    // 注册业务事件监听
    this.registerHubEvents()
  }

  /**
   * 注册 Hub 事件监听
   */
  private registerHubEvents(): void {
    if (!this.connection) return

    // 接收任务日志
    this.connection.on(HubEvent.RECEIVE_TASK_LOG, (data: TaskLogData) => {
      console.log('[SignalR] ReceiveTaskLog:', data)
      this.emit(HubEvent.RECEIVE_TASK_LOG, data)
    })

    // 接收任务状态
    this.connection.on(HubEvent.RECEIVE_TASK_STATUS, (data: TaskStatusData) => {
      console.log('[SignalR] ReceiveTaskStatus:', data)
      this.emit(HubEvent.RECEIVE_TASK_STATUS, data)
    })

    // 接收节点状态
    this.connection.on(HubEvent.RECEIVE_NODE_STATUS, (data: NodeStatusData) => {
      console.log('[SignalR] ReceiveNodeStatus:', data)
      this.emit(HubEvent.RECEIVE_NODE_STATUS, data)
    })
  }

  /**
   * 订阅事件
   */
  on<T = any>(event: string, callback: EventCallback<T>): void {
    if (!this.eventHandlers.has(event)) {
      this.eventHandlers.set(event, new Set())
    }
    this.eventHandlers.get(event)?.add(callback)
  }

  /**
   * 取消订阅事件
   */
  off<T = any>(event: string, callback: EventCallback<T>): void {
    this.eventHandlers.get(event)?.delete(callback)
  }

  /**
   * 触发事件回调
   */
  private emit(event: string, data: any): void {
    this.eventHandlers.get(event)?.forEach((callback) => {
      try {
        callback(data)
      } catch (error) {
        console.error(`Error in event callback for ${event}:`, error)
      }
    })
  }

  /**
   * 订阅任务日志
   */
  async subscribeTaskLogs(taskId: number): Promise<void> {
    if (!this.connection) {
      throw new Error('SignalR connection not established')
    }
    if (this.connection.state !== signalR.HubConnectionState.Connected) {
      throw new Error(`SignalR not connected, current state: ${this.connection.state}`)
    }
    try {
      await this.connection.invoke(HubMethod.SUBSCRIBE_TASK_LOGS, taskId)
      console.log(`Subscribed to task logs: ${taskId}`)
    } catch (error) {
      console.error(`Failed to subscribe task logs ${taskId}:`, error)
      throw error
    }
  }

  /**
   * 取消订阅任务日志
   */
  async unsubscribeTaskLogs(taskId: number): Promise<void> {
    if (!this.connection || this.connection.state !== signalR.HubConnectionState.Connected) {
      console.warn('SignalR not connected, skipping unsubscribe')
      return
    }
    try {
      await this.connection.invoke(HubMethod.UNSUBSCRIBE_TASK_LOGS, taskId)
      console.log(`Unsubscribed from task logs: ${taskId}`)
    } catch (error) {
      console.error(`Failed to unsubscribe task logs ${taskId}:`, error)
    }
  }

  /**
   * 订阅任务状态
   */
  async subscribeTaskStatus(pipelineInstanceId: number): Promise<void> {
    if (!this.connection) {
      throw new Error('SignalR connection not established')
    }
    if (this.connection.state !== signalR.HubConnectionState.Connected) {
      throw new Error(`SignalR not connected, current state: ${this.connection.state}`)
    }
    try {
      await this.connection.invoke(
        HubMethod.SUBSCRIBE_TASK_STATUS,
        pipelineInstanceId
      )
      console.log(`Subscribed to task status: ${pipelineInstanceId}`)
    } catch (error) {
      console.error(`Failed to subscribe task status ${pipelineInstanceId}:`, error)
      throw error
    }
  }

  /**
   * 取消订阅任务状态
   */
  async unsubscribeTaskStatus(pipelineInstanceId: number): Promise<void> {
    if (!this.connection || this.connection.state !== signalR.HubConnectionState.Connected) {
      console.warn('SignalR not connected, skipping unsubscribe')
      return
    }
    try {
      await this.connection.invoke(
        HubMethod.UNSUBSCRIBE_TASK_STATUS,
        pipelineInstanceId
      )
      console.log(`Unsubscribed from task status: ${pipelineInstanceId}`)
    } catch (error) {
      console.error(`Failed to unsubscribe task status ${pipelineInstanceId}:`, error)
    }
  }

  /**
   * 订阅节点状态
   */
  async subscribeNodeStatus(): Promise<void> {
    if (!this.connection) {
      throw new Error('SignalR connection not established')
    }
    if (this.connection.state !== signalR.HubConnectionState.Connected) {
      throw new Error(`SignalR not connected, current state: ${this.connection.state}`)
    }
    try {
      await this.connection.invoke(HubMethod.SUBSCRIBE_NODE_STATUS)
      console.log('Subscribed to node status')
    } catch (error) {
      console.error('Failed to subscribe node status:', error)
      throw error
    }
  }

  /**
   * 取消订阅节点状态
   */
  async unsubscribeNodeStatus(): Promise<void> {
    if (!this.connection || this.connection.state !== signalR.HubConnectionState.Connected) {
      console.warn('SignalR not connected, skipping unsubscribe')
      return
    }
    try {
      await this.connection.invoke(HubMethod.UNSUBSCRIBE_NODE_STATUS)
      console.log('Unsubscribed from node status')
    } catch (error) {
      console.error('Failed to unsubscribe node status:', error)
    }
  }

  /**
   * 订阅流水线实例（同时订阅日志和状态）
   */
  async subscribePipelineInstance(pipelineInstanceId: number): Promise<void> {
    if (!this.connection) {
      throw new Error('SignalR connection not established')
    }
    if (this.connection.state !== signalR.HubConnectionState.Connected) {
      throw new Error(`SignalR not connected, current state: ${this.connection.state}`)
    }
    try {
      await this.connection.invoke(
        HubMethod.SUBSCRIBE_PIPELINE_INSTANCE,
        pipelineInstanceId
      )
      console.log(`Subscribed to pipeline instance: ${pipelineInstanceId}`)
    } catch (error) {
      console.error(`Failed to subscribe pipeline instance ${pipelineInstanceId}:`, error)
      throw error
    }
  }

  /**
   * 取消订阅流水线实例
   */
  async unsubscribePipelineInstance(pipelineInstanceId: number): Promise<void> {
    if (!this.connection || this.connection.state !== signalR.HubConnectionState.Connected) {
      console.warn('SignalR not connected, skipping unsubscribe')
      return
    }
    try {
      await this.connection.invoke(
        HubMethod.UNSUBSCRIBE_PIPELINE_INSTANCE,
        pipelineInstanceId
      )
      console.log(`Unsubscribed from pipeline instance: ${pipelineInstanceId}`)
    } catch (error) {
      console.error(`Failed to unsubscribe pipeline instance ${pipelineInstanceId}:`, error)
    }
  }

  /**
   * 断开连接
   */
  async disconnect(): Promise<void> {
    if (this.connection) {
      await this.connection.stop()
      this.connection = null
      this.eventHandlers.clear()
      console.log('SignalR disconnected')
    }
  }

  /**
   * 检查连接状态
   */
  isConnected(): boolean {
    return this.connection?.state === signalR.HubConnectionState.Connected
  }

  /**
   * 获取连接状态
   */
  getState(): signalR.HubConnectionState | null {
    return this.connection?.state || null
  }
}

// 导出单例
export const signalRService = new SignalRService()

// 为了向后兼容，也导出为 wsService
export const wsService = signalRService
